From 58c2bea959b447b36f37757fd6a1a2ae8ea675c8 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Timm=20B=C3=A4der?= Date: Sat, 23 Feb 2019 07:50:51 +0100 Subject: [PATCH] gl renderer: Stop determining the matrix category ourselves Use the category we get from transform nodes and add ops_ API to supply one when we set a graphene_matrix_t directly. --- gsk/gl/gskglrenderer.c | 119 +++++++++---------- gsk/gl/gskglrenderops.c | 208 +++++++++++++++++++++------------ gsk/gl/gskglrenderopsprivate.h | 14 ++- 3 files changed, 195 insertions(+), 146 deletions(-) diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c index 24f5452491..4128953430 100644 --- a/gsk/gl/gskglrenderer.c +++ b/gsk/gl/gskglrenderer.c @@ -249,6 +249,8 @@ node_supports_transform (GskRenderNode *node) case GSK_OPACITY_NODE: case GSK_COLOR_MATRIX_NODE: case GSK_TEXTURE_NODE: + case GSK_TRANSFORM_NODE: + case GSK_CROSS_FADE_NODE: return TRUE; default: @@ -769,7 +771,6 @@ render_transform_node (GskGLRenderer *self, const graphene_matrix_t *node_transform = gsk_transform_node_peek_transform (node); GskRenderNode *child = gsk_transform_node_get_child (node); - switch (category) { case GSK_MATRIX_CATEGORY_IDENTITY: @@ -789,23 +790,9 @@ render_transform_node (GskGLRenderer *self, case GSK_MATRIX_CATEGORY_2D_AFFINE: { - const float scale = ops_get_scale (builder); - graphene_matrix_t transform, transformed_mv; - const float dx = builder->dx; - const float dy = builder->dy; - - graphene_matrix_init_from_matrix (&transform, node_transform); - graphene_matrix_multiply (&transform, builder->current_modelview, &transformed_mv); - graphene_matrix_translate (&transformed_mv, - &(graphene_point3d_t) { builder->dx * scale, builder->dy * scale, 0}); - - builder->dx = 0; - builder->dy = 0; - ops_push_modelview (builder, &transformed_mv); + ops_push_modelview (builder, node_transform, category); gsk_gl_renderer_add_render_ops (self, child, builder); ops_pop_modelview (builder); - builder->dx = dx; - builder->dy = dy; } break; @@ -814,8 +801,6 @@ render_transform_node (GskGLRenderer *self, case GSK_MATRIX_CATEGORY_INVERTIBLE: default: { - const float scale = ops_get_scale (builder); - graphene_matrix_t transform, transformed_mv; const float min_x = child->bounds.origin.x; const float min_y = child->bounds.origin.y; const float max_x = min_x + child->bounds.size.width; @@ -823,53 +808,56 @@ render_transform_node (GskGLRenderer *self, int texture_id; gboolean is_offscreen; - graphene_matrix_init_from_matrix (&transform, node_transform); - graphene_matrix_multiply (&transform, builder->current_modelview, &transformed_mv); - graphene_matrix_translate (&transformed_mv, - &(graphene_point3d_t) { builder->dx * scale, builder->dy * scale, 0}); - - ops_push_modelview (builder, &transformed_mv); - /* For non-trivial transforms, we draw everything on a texture and then - * draw the texture transformed. */ - /* TODO: We should compute a modelview containing only the "non-trivial" - * part (e.g. the rotation) and use that. We want to keep the scale - * for the texture. - */ - add_offscreen_ops (self, builder, - &child->bounds, - child, - &texture_id, &is_offscreen, - RESET_CLIP | RESET_OPACITY); - ops_set_texture (builder, texture_id); - ops_set_program (builder, &self->blit_program); - - if (is_offscreen) - { - const GskQuadVertex offscreen_vertex_data[GL_N_VERTICES] = { - { { min_x, min_y }, { 0, 1 }, }, - { { min_x, max_y }, { 0, 0 }, }, - { { max_x, min_y }, { 1, 1 }, }, - - { { max_x, max_y }, { 1, 0 }, }, - { { min_x, max_y }, { 0, 0 }, }, - { { max_x, min_y }, { 1, 1 }, }, - }; + ops_push_modelview (builder, node_transform, category); - ops_draw (builder, offscreen_vertex_data); + if (node_supports_transform (child)) + { + gsk_gl_renderer_add_render_ops (self, child, builder); } else { - const GskQuadVertex onscreen_vertex_data[GL_N_VERTICES] = { - { { min_x, min_y }, { 0, 0 }, }, - { { min_x, max_y }, { 0, 1 }, }, - { { max_x, min_y }, { 1, 0 }, }, - - { { max_x, max_y }, { 1, 1 }, }, - { { min_x, max_y }, { 0, 1 }, }, - { { max_x, min_y }, { 1, 0 }, }, - }; - - ops_draw (builder, onscreen_vertex_data); + /* For non-trivial transforms, we draw everything on a texture and then + * draw the texture transformed. */ + /* TODO: We should compute a modelview containing only the "non-trivial" + * part (e.g. the rotation) and use that. We want to keep the scale + * for the texture. + */ + add_offscreen_ops (self, builder, + &child->bounds, + child, + &texture_id, &is_offscreen, + RESET_CLIP | RESET_OPACITY); + ops_set_texture (builder, texture_id); + ops_set_program (builder, &self->blit_program); + + if (is_offscreen) + { + const GskQuadVertex offscreen_vertex_data[GL_N_VERTICES] = { + { { min_x, min_y }, { 0, 1 }, }, + { { min_x, max_y }, { 0, 0 }, }, + { { max_x, min_y }, { 1, 1 }, }, + + { { max_x, max_y }, { 1, 0 }, }, + { { min_x, max_y }, { 0, 0 }, }, + { { max_x, min_y }, { 1, 1 }, }, + }; + + ops_draw (builder, offscreen_vertex_data); + } + else + { + const GskQuadVertex onscreen_vertex_data[GL_N_VERTICES] = { + { { min_x, min_y }, { 0, 0 }, }, + { { min_x, max_y }, { 0, 1 }, }, + { { max_x, min_y }, { 1, 0 }, }, + + { { max_x, max_y }, { 1, 1 }, }, + { { min_x, max_y }, { 0, 1 }, }, + { { max_x, min_y }, { 1, 0 }, }, + }; + + ops_draw (builder, onscreen_vertex_data); + } } ops_pop_modelview (builder); @@ -1306,7 +1294,7 @@ render_outset_shadow_node (GskGLRenderer *self, op.op = OP_CLEAR; ops_add (builder, &op); prev_projection = ops_set_projection (builder, &item_proj); - ops_push_modelview (builder, &identity); + ops_set_modelview (builder, &identity, GSK_MATRIX_CATEGORY_IDENTITY); prev_viewport = ops_set_viewport (builder, &GRAPHENE_RECT_INIT (0, 0, texture_width, texture_height)); /* Draw outline */ @@ -2368,7 +2356,7 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self, break; case GSK_DEBUG_NODE: - gsk_gl_renderer_add_render_ops (self, + gsk_gl_renderer_add_render_ops (self, gsk_debug_node_get_child (node), builder); break; @@ -2523,7 +2511,7 @@ add_offscreen_ops (GskGLRenderer *self, op.op = OP_CLEAR; ops_add (builder, &op); prev_projection = ops_set_projection (builder, &item_proj); - ops_push_modelview (builder, &identity); + ops_set_modelview (builder, &identity, GSK_MATRIX_CATEGORY_IDENTITY); prev_viewport = ops_set_viewport (builder, &GRAPHENE_RECT_INIT (bounds->origin.x * scale, bounds->origin.y * scale, @@ -2783,7 +2771,8 @@ gsk_gl_renderer_do_render (GskRenderer *renderer, render_op_builder.current_viewport = *viewport; render_op_builder.current_opacity = 1.0f; render_op_builder.render_ops = self->render_ops; - ops_push_modelview (&render_op_builder, &modelview); + ops_set_modelview (&render_op_builder, &modelview, + scale_factor == 1 ? GSK_MATRIX_CATEGORY_IDENTITY : GSK_MATRIX_CATEGORY_2D_AFFINE); /* Initial clip is self->render_region! */ if (self->render_region != NULL) diff --git a/gsk/gl/gskglrenderops.c b/gsk/gl/gskglrenderops.c index 9fbc9ec405..ee5e19b479 100644 --- a/gsk/gl/gskglrenderops.c +++ b/gsk/gl/gskglrenderops.c @@ -63,63 +63,55 @@ static void extract_matrix_metadata (const graphene_matrix_t *m, OpsMatrixMetadata *md) { - graphene_vec3_t col1; - graphene_vec3_t col2; - - /* Translate */ - md->translate_x = graphene_matrix_get_value (m, 3, 0); - md->translate_y = graphene_matrix_get_value (m, 3, 1); - - /* Scale */ - graphene_vec3_init (&col1, - graphene_matrix_get_value (m, 0, 0), - graphene_matrix_get_value (m, 1, 0), - graphene_matrix_get_value (m, 2, 0)); - - graphene_vec3_init (&col2, - graphene_matrix_get_value (m, 0, 1), - graphene_matrix_get_value (m, 1, 1), - graphene_matrix_get_value (m, 2, 1)); - - md->scale_x = graphene_vec3_length (&col1); - md->scale_y = graphene_vec3_length (&col2); - - /* A simple matrix (in our case) is one that doesn't do anything but scale - * and/or translate. - * - * For orher matrices, we fall back to offscreen drawing. - */ - md->simple = TRUE; - { - static const guchar check_zero[4][4] = { - { 0, 1, 0, 1 }, /* If any of the values marked as '1' here is non-zero, */ - { 1, 0, 0, 1 }, /* We have to resort to offscreen drawing later on. */ - { 1, 1, 0, 1 }, - { 0, 0, 0, 0 }, - }; - int x, y; - - for (x = 0; x < 4; x ++) - for (y = 0; y < 4; y ++) - if (check_zero[y][x] && - graphene_matrix_get_value (m, y, x) != 0.0f) - { - md->simple = FALSE; - goto out; - } - } - -out: - md->only_translation = (md->simple && md->scale_x == 1 && md->scale_y == 1); + switch (md->category) + { + case GSK_MATRIX_CATEGORY_IDENTITY: + md->scale_x = 1; + md->scale_y = 1; + break; + + case GSK_MATRIX_CATEGORY_2D_TRANSLATE: + md->translate_x = graphene_matrix_get_value (m, 3, 0); + md->translate_y = graphene_matrix_get_value (m, 3, 1); + md->scale_x = 1; + md->scale_y = 1; + break; + + case GSK_MATRIX_CATEGORY_UNKNOWN: + case GSK_MATRIX_CATEGORY_ANY: + case GSK_MATRIX_CATEGORY_INVERTIBLE: + case GSK_MATRIX_CATEGORY_2D_AFFINE: + { + graphene_vec3_t col1; + graphene_vec3_t col2; + + md->translate_x = graphene_matrix_get_value (m, 3, 0); + md->translate_y = graphene_matrix_get_value (m, 3, 1); + + graphene_vec3_init (&col1, + graphene_matrix_get_value (m, 0, 0), + graphene_matrix_get_value (m, 1, 0), + graphene_matrix_get_value (m, 2, 0)); + + graphene_vec3_init (&col2, + graphene_matrix_get_value (m, 0, 1), + graphene_matrix_get_value (m, 1, 1), + graphene_matrix_get_value (m, 2, 1)); + + md->scale_x = graphene_vec3_length (&col1); + md->scale_y = graphene_vec3_length (&col2); + } + break; + default: + {} + } } - void ops_transform_bounds_modelview (const RenderOpBuilder *builder, const graphene_rect_t *src, graphene_rect_t *dst) { - const float scale = ops_get_scale (builder); const MatrixStackEntry *head; g_assert (builder->mv_stack != NULL); @@ -127,34 +119,32 @@ ops_transform_bounds_modelview (const RenderOpBuilder *builder, head = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 1); - if (head->metadata.only_translation) + switch (head->metadata.category) { + case GSK_MATRIX_CATEGORY_IDENTITY: *dst = *src; - graphene_rect_offset (dst, - head->metadata.translate_x, - head->metadata.translate_y); - } - else - { + break; + + case GSK_MATRIX_CATEGORY_2D_TRANSLATE: + *dst = *src; + dst->origin.x += head->metadata.translate_x; + dst->origin.y += head->metadata.translate_y; + break; + + /* TODO: Handle scale */ + case GSK_MATRIX_CATEGORY_2D_AFFINE: + case GSK_MATRIX_CATEGORY_UNKNOWN: + case GSK_MATRIX_CATEGORY_ANY: + case GSK_MATRIX_CATEGORY_INVERTIBLE: + default: graphene_matrix_transform_bounds (builder->current_modelview, src, dst); - } - - graphene_rect_offset (dst, builder->dx * scale, builder->dy * scale); -} -gboolean -ops_modelview_is_simple (const RenderOpBuilder *builder) -{ - const MatrixStackEntry *head; - - g_assert (builder->mv_stack != NULL); - g_assert (builder->mv_stack->len >= 1); - - head = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 1); + } - return head->metadata.simple; + dst->origin.x += builder->dx * head->metadata.scale_x; + dst->origin.y += builder->dy * head->metadata.scale_y; } void @@ -303,8 +293,8 @@ ops_has_clip (RenderOpBuilder *self) } static void -ops_set_modelview (RenderOpBuilder *builder, - const graphene_matrix_t *modelview) +ops_set_modelview_internal (RenderOpBuilder *builder, + const graphene_matrix_t *modelview) { RenderOp op; @@ -338,9 +328,12 @@ ops_set_modelview (RenderOpBuilder *builder, builder->current_program_state->modelview = *modelview; } +/* This sets the modelview to the given one without looking at the + * one that's currently set */ void -ops_push_modelview (RenderOpBuilder *builder, - const graphene_matrix_t *mv) +ops_set_modelview (RenderOpBuilder *builder, + const graphene_matrix_t *mv, + GskMatrixCategory mv_category) { MatrixStackEntry *entry; @@ -353,10 +346,64 @@ ops_push_modelview (RenderOpBuilder *builder, entry = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 1); entry->matrix = *mv; + entry->metadata.category = mv_category; + + entry->metadata.dx_before = builder->dx; + entry->metadata.dy_before = builder->dy; + extract_matrix_metadata (mv, &entry->metadata); + + builder->dx = 0; + builder->dy = 0; + builder->current_modelview = &entry->matrix; + ops_set_modelview_internal (builder, &entry->matrix); +} + +/* This sets the given modelview to the one we get when multiplying + * the given modelview with the current one. */ +void +ops_push_modelview (RenderOpBuilder *builder, + const graphene_matrix_t *mv, + GskMatrixCategory mv_category) +{ + float scale = ops_get_scale (builder); + MatrixStackEntry *entry; + + if (G_UNLIKELY (builder->mv_stack == NULL)) + builder->mv_stack = g_array_new (FALSE, TRUE, sizeof (MatrixStackEntry)); + + g_assert (builder->mv_stack != NULL); + + g_array_set_size (builder->mv_stack, builder->mv_stack->len + 1); + entry = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 1); + + if (G_LIKELY (builder->mv_stack->len >= 2)) + { + const MatrixStackEntry *cur; + + cur = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 2); + /* Multiply given matrix with current modelview */ + + graphene_matrix_multiply (mv, &cur->matrix, &entry->matrix); + graphene_matrix_translate (&entry->matrix, + &(graphene_point3d_t) { builder->dx * scale, builder->dy * scale, 0}); + + entry->metadata.category = MIN (mv_category, cur->metadata.category); + } + else + { + entry->matrix = *mv; + entry->metadata.category = mv_category; + } + + entry->metadata.dx_before = builder->dx; + entry->metadata.dy_before = builder->dy; + extract_matrix_metadata (mv, &entry->metadata); + builder->dx = 0; + builder->dy = 0; builder->current_modelview = &entry->matrix; - ops_set_modelview (builder, mv); + ops_set_modelview_internal (builder, &entry->matrix); } void @@ -368,6 +415,10 @@ ops_pop_modelview (RenderOpBuilder *builder) g_assert (builder->mv_stack); g_assert (builder->mv_stack->len >= 1); + head = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 1); + builder->dx = head->metadata.dx_before; + builder->dy = head->metadata.dy_before; + builder->mv_stack->len --; head = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 1); m = &head->matrix; @@ -375,7 +426,7 @@ ops_pop_modelview (RenderOpBuilder *builder) if (builder->mv_stack->len >= 1) { builder->current_modelview = m; - ops_set_modelview (builder, m); + ops_set_modelview_internal (builder, m); } else { @@ -684,6 +735,9 @@ ops_draw (RenderOpBuilder *builder, builder->buffer_size += sizeof (GskQuadVertex) * GL_N_VERTICES; } +/* The offset is only valid for the current modelview. + * Setting a new modelview will add the offset to that matrix + * and reset the internal offset to 0. */ void ops_offset (RenderOpBuilder *builder, float x, diff --git a/gsk/gl/gskglrenderopsprivate.h b/gsk/gl/gskglrenderopsprivate.h index 67c50641e1..e80d688259 100644 --- a/gsk/gl/gskglrenderopsprivate.h +++ b/gsk/gl/gskglrenderopsprivate.h @@ -8,6 +8,7 @@ #include "gskgldriverprivate.h" #include "gskroundedrectprivate.h" #include "gskglrendererprivate.h" +#include "gskrendernodeprivate.h" #define GL_N_VERTICES 6 #define GL_N_PROGRAMS 11 @@ -21,8 +22,10 @@ typedef struct float scale_x; float scale_y; - guint simple : 1; - guint only_translation : 1; + float dx_before; + float dy_before; + + GskMatrixCategory category; } OpsMatrixMetadata; typedef struct @@ -277,9 +280,12 @@ void ops_dump_framebuffer (RenderOpBuilder *builder, void ops_finish (RenderOpBuilder *builder); void ops_push_modelview (RenderOpBuilder *builder, - const graphene_matrix_t *mv); + const graphene_matrix_t *mv, + GskMatrixCategory mv_category); +void ops_set_modelview (RenderOpBuilder *builder, + const graphene_matrix_t *mv, + GskMatrixCategory mv_category); void ops_pop_modelview (RenderOpBuilder *builder); -gboolean ops_modelview_is_simple (const RenderOpBuilder *builder); float ops_get_scale (const RenderOpBuilder *builder); void ops_set_program (RenderOpBuilder *builder, -- 2.30.2